home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XS.ZIP / MAIL / RMAIL.C < prev    next >
C/C++ Source or Header  |  1992-12-05  |  40KB  |  994 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       r m a i l . c                                                */
  3. /*                                                                    */
  4. /*       Delivery agent for UUPC/extended                             */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1992 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*--------------------------------------------------------------------*/
  18. /*                          RCS Information                           */
  19. /*--------------------------------------------------------------------*/
  20.  
  21. /*
  22.  *    $Id: RMAIL.C 1.5 1992/12/05 23:38:43 ahd Exp $
  23.  *
  24.  *    $Log: RMAIL.C $
  25.  * Revision 1.5  1992/12/05  23:38:43  ahd
  26.  * Let logger close the log, not rmail
  27.  *
  28.  * Revision 1.4  1992/12/04  01:00:27  ahd
  29.  * Add copyright messages
  30.  *
  31.  */
  32.  
  33. /*--------------------------------------------------------------------*/
  34. /*    Function:   Stand alone mail delivery module for                */
  35. /*                UUPC/extended                                       */
  36. /*    Language:   Borland C++ 3.1 (ANSI C mode) or Microsoft C 6.0.   */
  37. /*    Arguments:  One or more addresses to deliver mail to            */
  38. /*                or "-t" to direct rmail to read the addresses       */
  39. /*                from the RFC-822 header.                            */
  40. /*                A third mode of operation is to specify '-w' and/   */
  41. /*                or '-s subject' followed by one or more addresses   */
  42. /*                with optional carbon copy flags (-c or -b) before   */
  43. /*                additional addresses.  This causes rmail to         */
  44. /*                function like a bare bones batch version of the     */
  45. /*                MAIL program; a valid RFC-822 header is generated   */
  46. /*                and the mail is delivered, aliases are not expanded */
  47. /*                and the mail is not locally logged.  (The current   */
  48. /*                user id as the from address is used unless the      */
  49. /*                environment variable LOGNAME is set, in which case  */
  50. /*                it is used.)                                        */
  51. /*                Optional argument "-f" to denote file to read in    */
  52. /*                place of stdin.                                     */
  53. /*                Optional argument "-F" to denote file to read in    */
  54. /*                place of stdin and DELETE after readering.          */
  55. /*                Optional argument "-x" to for debug level           */
  56. /*    Input:      mail to be delivered, with RFC-822 header, on       */
  57. /*                stdin.                                              */
  58. /*    Output:     'From' and 'Received:' headers are added,           */
  59. /*                'Bcc:' headers are removed, and the mail is         */
  60. /*                delivered to one or more local users and/or         */
  61. /*                one or more remote users.                           */
  62. /*    Exit code:  0  Success                                          */
  63. /*                1  One or more letters not delivered                */
  64. /*                2  No mail delivered                                */
  65. /*                3 Configuration file error                          */
  66. /*                4 Invalid option/help specified                     */
  67. /*                5 Invalid option/help specified                     */
  68. /*                                                                    */
  69. /*    Note:       When parsing RFC-822 headers, this program          */
  70. /*                expects them to be "well-behaved", that is in       */
  71. /*                format generated by UUPC/extended.  This implies:   */
  72. /*                                                                    */
  73. /*                      One address per line                          */
  74. /*                                                                    */
  75. /*                      Resent- headers, if any, before the original  */
  76. /*                      headers.                                      */
  77. /*                                                                    */
  78. /*                      From: header must precede To: header.         */
  79. /*                                                                    */
  80. /*                      To: header must precede Cc: and Bcc: headers. */
  81. /*                                                                    */
  82. /*                      Cc: and Bcc: headers must be together (one    */
  83. /*                      after the other)                              */
  84. /*                                                                    */
  85. /*                      The MUA has prefixed any obsolete Resent-     */
  86. /*                      headers by X-                                 */
  87. /*                                                                    */
  88. /*    Note:       The "-t" flag is supported by BSD sendmail for the  */
  89. /*                purpose listed above, but we also turn use it to    */
  90. /*                control other special options, all of which         */
  91. /*                basically cause the program to act more like a      */
  92. /*                local mailer than a remote mailer; these options    */
  93. /*                include:                                            */
  94. /*                                                                    */
  95. /*                      Stripping off blind carbon copies             */
  96. /*                                                                    */
  97. /*                      Generating the UUCP From line differently     */
  98. /*--------------------------------------------------------------------*/
  99.  
  100. /*--------------------------------------------------------------------*/
  101. /*                        System include files                        */
  102. /*--------------------------------------------------------------------*/
  103.  
  104. #include <stdio.h>
  105. #include <ctype.h>
  106. #include <io.h>
  107. #include <stdlib.h>
  108. #include <string.h>
  109. #include <time.h>
  110. #include <signal.h>
  111.  
  112. /*--------------------------------------------------------------------*/
  113. /*                     Application include files                      */
  114. /*--------------------------------------------------------------------*/
  115.  
  116. #include "lib.h"
  117. #include "address.h"
  118. #include "arpadate.h"
  119. #include "deliver.h"
  120. #include "getopt.h"
  121. #include "hlib.h"
  122. #include "hostable.h"
  123. #include "logger.h"
  124. #include "security.h"
  125. #include "usertabl.h"
  126. #include "timestmp.h"
  127. #include "catcher.h"
  128.  
  129. /*--------------------------------------------------------------------*/
  130. /*                           Local defines                            */
  131. /*--------------------------------------------------------------------*/
  132.  
  133. #define  MOPLEN      10          /* Length of formatted header lines */
  134. #define  UUCPFROM    "From "     /* Length of UUCP incoming mail     */
  135.  
  136. /*--------------------------------------------------------------------*/
  137. /*                   Prototypes for internal files                    */
  138. /*--------------------------------------------------------------------*/
  139.  
  140. static boolean CopyTemp( void );
  141.  
  142. static void ParseFrom( void );
  143.  
  144. static char **Parse822( boolean *header,
  145.                         size_t *count);
  146.  
  147. static void Terminate( const int rc);
  148.  
  149.  static void PutHead( const char *label,
  150.                       const char *operand,
  151.                       FILE *stream,
  152.                       const boolean resent);
  153.  
  154. static boolean DaemonMail( const char *subject,
  155.                            char **address,
  156.                            int count );
  157.  
  158.  
  159.  static void usage( void );
  160.  
  161. /*--------------------------------------------------------------------*/
  162. /*                          Global variables                          */
  163. /*--------------------------------------------------------------------*/
  164.  
  165.  currentfile();               /* Declare file name for checkref()    */
  166.  char *tempname = NULL;       /* Pointer to temporary input file     */
  167.  char *namein = CONSOLE;
  168.  FILE *datain = stdin;        /* Handle for reading input mail       */
  169.  FILE *dataout = NULL;        /* Handle for the output of mail       */
  170.  char fromuser[MAXADDR] = ""; /* User id of originator               */
  171.  char fromnode[MAXADDR] = ""; /* Node id of originator               */
  172.  char *now;                   /* Time stamp for Received: banner     */
  173.  
  174.  static char received[] = "Received:";
  175.  static char receivedlen = sizeof( received) - 1;
  176.  
  177. /*--------------------------------------------------------------------*/
  178. /*                            main program                            */
  179. /*--------------------------------------------------------------------*/
  180.  
  181. void main(int argc, char **argv)
  182. {
  183.    boolean ReadHeader = FALSE;   /* TRUE = Parse RFC-822 headers      */
  184.  
  185.    int  option;                  /* For parsing option list           */
  186.    char **address;               /* Pointer to list of target
  187.                                     addresses                         */
  188.    char *token;
  189.    size_t addressees;            /* Number of targets in address      */
  190.    size_t count;                 /* Loop variable for delivery        */
  191.    size_t delivered = 0;         /* Count of successfull deliveries   */
  192.    boolean header = TRUE;
  193.    boolean DeleteInput = FALSE;
  194.  
  195.    boolean daemon = FALSE;
  196.  
  197.    char *subject = NULL;
  198.  
  199. /*--------------------------------------------------------------------*/
  200. /*    Make a copy of the Borland copyright for debugging purposes     */
  201. /*--------------------------------------------------------------------*/
  202.  
  203. #if defined(__CORE__)
  204.    copywrong = strdup(copyright);
  205.    checkref(copywrong);
  206. #endif
  207.  
  208.    banner( argv);
  209.  
  210.    now = arpadate();          /* Set the current date                */
  211.    debuglevel = -1;           /* Set default so we can detect it     */
  212.  
  213. /*--------------------------------------------------------------------*/
  214. /* Load the UUPC/extended configuration file, and exit if any errors  */
  215. /*--------------------------------------------------------------------*/
  216.  
  217.    if (!configure(B_MTA))
  218.       Terminate(3);
  219.  
  220. /*--------------------------------------------------------------------*/
  221. /*                    Handle control-C interrupts                     */
  222. /*--------------------------------------------------------------------*/
  223.  
  224.     if( signal( SIGINT, ctrlchandler ) == SIG_ERR )
  225.     {
  226.         printmsg( 0, "Couldn't set SIGINT\n" );
  227.         panic();
  228.     }
  229.  
  230. /*--------------------------------------------------------------------*/
  231. /*                       Begin logging messages                       */
  232. /*--------------------------------------------------------------------*/
  233.  
  234.    openlog( NULL );
  235.  
  236. /*--------------------------------------------------------------------*/
  237. /*                      Parse our operand flags                       */
  238. /*--------------------------------------------------------------------*/
  239.  
  240.    while ((option = getopt(argc, argv, "ws:tF:f:x:")) != EOF)
  241.    {
  242.       switch (option) {
  243.       case 'w':
  244.          daemon = TRUE;
  245.          break;
  246.  
  247.       case 's':
  248.          subject = optarg;
  249.          daemon = TRUE;
  250.          break;
  251.  
  252.       case 't':
  253.          ReadHeader = TRUE;
  254.          break;
  255.  
  256.       case 'x':
  257.          debuglevel = atoi(optarg);
  258.          break;
  259.  
  260.       case 'F':
  261.          DeleteInput = TRUE;
  262.       case 'f':
  263.          namein = optarg;
  264.          datain = FOPEN(namein , "r", TEXT);
  265.          break;
  266.  
  267.       case '?':
  268.          usage();
  269.          Terminate(4);
  270.       } /* switch */
  271.    } /* while */
  272.  
  273.    if ( debuglevel > 1 )
  274.    {
  275.       for ( count = 1; (int) count < argc; count ++)
  276.          printmsg(4,"rmail argv[%d] = \"%s\"", count, argv[count] );
  277.    } /* if ( debuglevel > 4 ) */
  278.  
  279.    if ((optind == argc) != ReadHeader)
  280.    {
  281.       puts("Missing/extra parameter(s) at end.");
  282.       Terminate(4);
  283.    }
  284.  
  285.    remoteMail = ! (ReadHeader || daemon);
  286.                               /* If not reading headers, must be in
  287.                                  normal rmail mode ...               */
  288.  
  289. /*--------------------------------------------------------------------*/
  290. /*    If in local mode and the user doesn't want output, suppress     */
  291. /*    routine delivery messages                                       */
  292. /*--------------------------------------------------------------------*/
  293.  
  294.    if ( debuglevel == -1 )
  295.    {
  296.       if (remoteMail)
  297.          debuglevel = 1;
  298.       else
  299.          debuglevel = (int) bflag[F_VERBOSE];
  300.    }
  301.  
  302. /*--------------------------------------------------------------------*/
  303. /*               Verify we have input stream available                */
  304. /*--------------------------------------------------------------------*/
  305.  
  306.    if (datain == NULL )
  307.    {
  308.       printerr(namein);
  309.       Terminate(3);
  310.    } /* if */
  311.  
  312. /*--------------------------------------------------------------------*/
  313. /*                   Open up the output data stream                   */
  314. /*--------------------------------------------------------------------*/
  315.  
  316.    tempname = mktempname( NULL , "TMP");
  317.    dataout = FOPEN(tempname, "w", TEXT);
  318.  
  319.    if (dataout == NULL)
  320.    {
  321.       printmsg(0,"Cannot open temporary file \"%s\" for output",
  322.             tempname);
  323.       Terminate(5);
  324.    } /* if */
  325.  
  326. /*--------------------------------------------------------------------*/
  327. /*   If in local mail mode, make up a list of addresses to mail to    */
  328. /*--------------------------------------------------------------------*/
  329.  
  330.    if ( daemon )
  331.    {
  332.       addressees = argc - optind;
  333.       address = &argv[optind];
  334.       DaemonMail( subject, address, addressees );
  335.       header = FALSE;
  336.    }
  337.    else if (ReadHeader)
  338.       address = Parse822( &header, &addressees );
  339.    else {
  340.       ParseFrom();               /* Copy remote header instead       */
  341.       addressees = argc - optind;
  342.       address = &argv[optind];
  343.    } /* if */
  344.  
  345.    if ( addressees == 0 )        /* Can we deliver mail?             */
  346.    {
  347.       printmsg(0, "No addressees to deliver to!");
  348.       Terminate( 2 );            /* No --> Execute punt formation    */
  349.    }
  350.  
  351. /*--------------------------------------------------------------------*/
  352. /*       Copy the rest of the input file into our holding tank        */
  353. /*--------------------------------------------------------------------*/
  354.  
  355.    header = CopyTemp( ) && header ;
  356.    if (header)                   /* Was the header ever terminated?  */
  357.    {
  358.       printmsg(0,"rmail: Improper header, adding trailing newline");
  359.       fputc('\n', dataout);      /* If not, it is now ...            */
  360.    }
  361.  
  362.    fclose(datain);
  363.    fclose(dataout);
  364.  
  365.    if (DeleteInput)              /* Make room for more data on disk  */
  366.       remove(namein);
  367.  
  368. /*--------------------------------------------------------------------*/
  369. /*        Determine requestor node and user id for remote mail        */
  370. /*--------------------------------------------------------------------*/
  371.  
  372.  
  373. /*--------------------------------------------------------------------*/
  374. /*                    Perform delivery of the mail                    */
  375. /*--------------------------------------------------------------------*/
  376.  
  377.    while ((token = strpbrk(tempname ,"/")) != NULL)
  378.       *token = '\\';
  379.  
  380.    for ( count = 0; count < addressees; count++)
  381.          if ( *address[count] == '-')
  382.             delivered ++;     /* Ignore option flags on delivery     */
  383.          else
  384.             delivered += Deliver(tempname, address[count], FALSE, TRUE);
  385.  
  386. /*--------------------------------------------------------------------*/
  387. /*                       Terminate the program                        */
  388. /*--------------------------------------------------------------------*/
  389.  
  390.    printmsg(8,"rmail: %d addressees, delivered to %d mailboxes",
  391.             addressees, delivered);
  392.  
  393.    if ( delivered >= addressees )
  394.       Terminate( 0 );         /* All mail delivered                  */
  395.    else if ( delivered == 0 )
  396.       Terminate( 2 );         /* No mail delivered                   */
  397.    else
  398.       Terminate (1 );         /* Some mail delivered                 */
  399.  
  400. } /* main */
  401.  
  402. /*--------------------------------------------------------------------*/
  403. /*    T e r m i n a t e                                               */
  404. /*                                                                    */
  405. /*    Cleanup open files and return to operating system               */
  406. /*--------------------------------------------------------------------*/
  407.  
  408. static void Terminate( const int rc)
  409. {
  410.    if (tempname != NULL)         /* Did temporary file get named?    */
  411.    {
  412.       if (datain != stdin)       /* Non-standard input?              */
  413.         fclose(stdin);           /* Yes --> Close it                 */
  414.       remove(tempname);          /* Purge temporary file, if exists  */
  415.    } /* if */
  416.  
  417.    exit( rc );                   /* Return to operating systems      */
  418. }  /* Terminate */
  419.  
  420. /*--------------------------------------------------------------------*/
  421. /*    P a r s e F r o m                                               */
  422. /*                                                                    */
  423. /*    Read the from address of incoming data from UUCP                */
  424. /*--------------------------------------------------------------------*/
  425.  
  426. static void ParseFrom()
  427. {
  428.    static char from[] = "From ";
  429.    static char remote[] = "remote from ";
  430.    static int  remotelen = sizeof remote - 1;
  431.    static int  fromlen = sizeof from - 1;
  432.    char *token;
  433.    char buf[BUFSIZ];
  434.    boolean hit;
  435.  
  436. /*--------------------------------------------------------------------*/
  437. /*                Use UUXQT Information, if available                 */
  438. /*--------------------------------------------------------------------*/
  439.  
  440.    token = getenv( UU_MACHINE );
  441.    if ( token == NULL )
  442.       *fromnode = '\0';
  443.    else {
  444.       strncpy( fromnode, token , sizeof fromnode );
  445.       fromnode[ sizeof fromnode - 1 ] = '\0';
  446.    }
  447.  
  448.    fgets(buf, BUFSIZ , datain);
  449.    hit = equaln(buf, from, fromlen );
  450.  
  451.    if (hit)
  452.    {
  453.       int nodelen = strlen( fromnode ) + 1; /* Plus ! */
  454.       char *s;
  455.       token = strtok( &buf[ fromlen ], " ");
  456.       s = strtok( NULL, "\n");
  457.  
  458.       if (strlen( token ) + nodelen >= MAXADDR)
  459.       {
  460.          char *next;
  461.          token = strtok( token, "!" );
  462.  
  463.          while ((next = strtok( NULL , "!")) != NULL )
  464.          {
  465.             token = next;
  466.             if (strlen( next ) + nodelen < MAXADDR)
  467.                break;
  468.          } /* while */
  469.       } /* if */
  470.  
  471.       strncpy(fromuser, token , sizeof fromuser );
  472.       fromuser[ sizeof fromuser - nodelen ] = '\0';
  473.  
  474.       if ( *fromnode == '\0')
  475.       {
  476.          while ( *s != '\0')
  477.          {
  478.             if equaln(s, remote, remotelen)
  479.                break;
  480.             else
  481.                s++;
  482.          } /* while */
  483.          strncpy( fromnode ,
  484.                 (*s == '\0') ? E_nodename : s + remotelen ,
  485.                  sizeof fromnode );
  486.          fromnode[ sizeof fromnode -1 ] = '\0';
  487.       } /* if ( *fromnode != '\0') */
  488.  
  489.    } /* if */
  490.    else {
  491.       if ( *fromnode == '\0')
  492.          strcpy(fromnode, E_nodename );
  493.       strcpy(fromuser, "/dev/null");
  494.    } /* else */
  495.  
  496. /*--------------------------------------------------------------------*/
  497. /*       Generate required "From " and "Received" header lines        */
  498. /*--------------------------------------------------------------------*/
  499.  
  500.    fprintf(dataout,"%-10s from %s by %s (%s %s) with UUCP;\n%-10s %s\n",
  501.             "Received:", fromnode, E_domain, compilep, compilev,
  502.             " ", now);
  503.  
  504. /*--------------------------------------------------------------------*/
  505. /*    If what we read wasn't a From line, write into the new file     */
  506. /*--------------------------------------------------------------------*/
  507.  
  508.    if (!hit)
  509.    {
  510.       fputs(buf, dataout);
  511.       if (ferror(dataout))
  512.       {
  513.          printerr(tempname);
  514.          Terminate(3);
  515.       } /* if */
  516.    } /* if */
  517.  
  518. /*--------------------------------------------------------------------*/
  519. /*              Determine the requestor user id and node              */
  520. /*--------------------------------------------------------------------*/
  521.  
  522.    token = getenv( UU_USER ); /* Get exactly what remote told us     */
  523.  
  524.    if ( token != NULL )
  525.    {                     /* Use exactly what remote told us     */
  526.       ruser = strtok( token , WHITESPACE );
  527.       rnode = strtok( NULL  , WHITESPACE );
  528.    } /* else */
  529.  
  530.    if ((rnode == NULL) || (strchr(rnode,'.') == NULL ))
  531.                               /* Did it tell us the domain?          */
  532.    {                          /* No --> Use from information         */
  533.       char node[MAXADDR];
  534.       char user[MAXADDR];
  535.  
  536.       sprintf(buf ,"%s!%s", fromnode, fromuser);
  537.       user_at_node(buf , buf, node, user);
  538.       ruser = newstr( user );
  539.       rnode = newstr( node );
  540.    }
  541.  
  542.    uuser = "uucp";            /* Effective id is always our daemon   */
  543.  
  544. }  /* ParseFrom */
  545.  
  546. /*--------------------------------------------------------------------*/
  547. /*    P a r s e 8 2 2                                                 */
  548. /*                                                                    */
  549. /*    Parse an RFC-822 header generated by that esteemed mail user    */
  550. /*    agent, UUPC/extended's MAIL.                                    */
  551. /*                                                                    */
  552. /*    Note that we parse the header in the format we KNOW that UUPC   */
  553. /*    generated it in:  "To:", "Cc:", "Bcc:", optionally prefixed     */
  554. /*    by "Resent-".  We also know that mail comes in one address      */
  555. /*    per line, and that the Resent- headers, if any, precede the     */
  556. /*    original headers.                                               */
  557. /*--------------------------------------------------------------------*/
  558.  
  559. static char **Parse822( boolean *header,
  560.                         size_t *count)
  561. {
  562.  
  563. /*--------------------------------------------------------------------*/
  564. /*  Define the headers we will be examining and variables for their   */
  565. /*                              lengths                               */
  566. /*--------------------------------------------------------------------*/
  567.  
  568.    static char *to     = "Resent-To:";
  569.    static char *cc     = "Resent-Cc:";
  570.    static char *bcc    = "Resent-Bcc:";
  571.    static char *resent = "Resent-";
  572.    static char *from   = "Resent-From:";
  573.  
  574.    size_t tolen;
  575.    size_t cclen;
  576.    size_t bcclen;
  577.    size_t resentlen =  strlen(resent);
  578.    size_t offset = resentlen; /* Subscript for examining headers,
  579.                                  which allows us to ignore Resent-   */
  580.    size_t fromlen =  strlen( &from[offset] );
  581.    size_t allocated = 5;      /* Reasonable first size for address   */
  582.                               /* Note: MUST BE AT LEAST 2 because we
  583.                                        add 50% below!                */
  584.    boolean blind = FALSE;
  585.  
  586.    char **addrlist = calloc( sizeof *addrlist , allocated);
  587.    char buf[BUFSIZ];          /* Input buffer for reading header     */
  588.    char address[MAXADDR];     /* Buffer for parsed address           */
  589.    char path[MAXADDR];
  590.    char *token;               /* For parsing line in buf             */
  591.    struct HostTable *hostp;
  592.  
  593. /*--------------------------------------------------------------------*/
  594. /*                          Begin processing                          */
  595. /*--------------------------------------------------------------------*/
  596.  
  597.    *count = 0;                /* No addresses discovered yet         */
  598.    checkref(addrlist);        /* Verify we had room for the list     */
  599.  
  600.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  601.               "Received:",E_domain,compilep, compilev,
  602.               " ", now );
  603.  
  604. /*--------------------------------------------------------------------*/
  605. /*                        Find the From: line                         */
  606. /*--------------------------------------------------------------------*/
  607.  
  608.    do {
  609.       if (fgets( buf, BUFSIZ, datain) == NULL)  /* End of file?      */
  610.          return NULL;         /* Yes --> Very bad, report error      */
  611.       fputs(buf, dataout );
  612.       if (*buf == '\n')       /* End of the header?                  */
  613.          return NULL;         /* Yes --> Very bad, report error      */
  614.       else if (equalni(resent, buf, resentlen))
  615.       {
  616.          offset = 0;
  617.          fromlen = strlen(&from[offset]);
  618.       } /* if */
  619.       else if (equalni(received, buf, receivedlen))
  620.          hops++;
  621.    } while (!equalni(&from[offset], buf, fromlen));
  622.  
  623.    strtok( buf , WHITESPACE);    /* Drop the leading token           */
  624.    token = strtok( NULL, "\n");  /* Get the token with From: addr    */
  625.    ExtractAddress( address, token, FALSE );
  626.                                  /* Get the From: address itself     */
  627.    user_at_node(address, path, fromnode, fromuser);
  628.                                  /* Separate portions of the address */
  629.  
  630. /*--------------------------------------------------------------------*/
  631. /*               Generate a Sender: line if we need it                */
  632. /*--------------------------------------------------------------------*/
  633.  
  634.    if (equal(fromnode,HostAlias(E_fdomain))) /* Same as hidden site? */
  635.       strcpy(fromnode, E_nodename);/* Yes --> Declare as local system  */
  636.  
  637.    hostp = checkname( fromnode );   /* Look up real system name      */
  638.  
  639.    if (!equal(fromuser,E_mailbox) ||
  640.        (hostp == BADHOST) || (hostp->hstatus != localhost))
  641.    {
  642.       sprintf(buf, "%s <%s@%s>", E_name, E_mailbox, E_fdomain );
  643.       PutHead("Sender:", buf, dataout , offset == 0 );
  644.    } /* if */
  645.  
  646. /*--------------------------------------------------------------------*/
  647. /*      Set UUCP requestor name while we've got the information       */
  648. /*--------------------------------------------------------------------*/
  649.  
  650.    if ((hostp != BADHOST) && (hostp->hstatus == localhost))
  651.       rnode = bflag[F_BANG] ? E_nodename : E_fdomain;
  652.                               /* Use full domain address, if possible */
  653.    else
  654.       rnode = fromnode;
  655.  
  656.    uuser = ruser = fromuser;  /* User and requestor always the same
  657.                                  for locally generated mail          */
  658.  
  659. /*--------------------------------------------------------------------*/
  660. /*                       Generate a message-id                        */
  661. /*--------------------------------------------------------------------*/
  662.  
  663.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , E_nodename, E_domain);
  664.    PutHead("Message-ID:", buf, dataout , offset == 0 );
  665.    PutHead(NULL, NULL, dataout , FALSE );
  666.  
  667. /*--------------------------------------------------------------------*/
  668. /*                 Locate the To: or Resent-To: line                  */
  669. /*--------------------------------------------------------------------*/
  670.  
  671.    tolen =    strlen( &to[offset] );
  672.  
  673.    do {
  674.       if (fgets( buf, BUFSIZ, datain ) == NULL)  /* End of file?     */
  675.          return NULL;         /* Yes --> Very bad, report error      */
  676.       fputs(buf, dataout );
  677.       if (*buf == '\n')       /* End of the header?                  */
  678.          return NULL;         /* Yes --> Very bad, report error      */
  679.       else if (equalni(received, buf, receivedlen))
  680.          hops++;
  681.    } while ( !equalni(&to[offset] , buf , tolen ));
  682.  
  683.    token = strpbrk( buf ," \t");
  684.  
  685. /*--------------------------------------------------------------------*/
  686. /*                Proccess the rest of the addressees                 */
  687. /*--------------------------------------------------------------------*/
  688.  
  689.    cclen =    strlen( &cc[offset] );
  690.    bcclen =   strlen( &bcc[offset] );
  691.  
  692.    do {
  693.       if (allocated == (*count+1))  /* Do we have room for addr?     */
  694.       {
  695.          allocated += allocated / 2;   /* Choose larger array size   */
  696.          addrlist = realloc( addrlist ,
  697.                              allocated * sizeof( *addrlist ));
  698.          checkref(addrlist);  /* Verify the allocation worked        */
  699.       } /* if */
  700.  
  701.       ExtractAddress( address, token, FALSE );  /* Get address itself*/
  702.       if (!strlen(address))
  703.       {
  704.          printmsg(0,"Could not locate expected address in header");
  705.          *count = 0;
  706.          return NULL;
  707.       } /* if */
  708.       else {
  709.          addrlist[*count] = newstr( address );
  710.                               /* Save permanent copy of address      */
  711.          checkref( addrlist[*count] ); /* Verify strdup worked       */
  712.          printmsg(4,"address[%d]= \"%s\"",*count, address);
  713.          *count += 1;         /* Flag we got the address             */
  714.       } /* else */
  715.  
  716.       if (fgets( buf, BUFSIZ, datain ) == NULL) /* End of file?      */
  717.          token = NULL;        /* Yes --> Odd, but no major problem   */
  718.       else if (*buf == '\n')  /* End of the header?                  */
  719.       {
  720.          token = NULL;        /* Yes --> Exit loop                   */
  721.          *header = FALSE;     /* Report to caller the header is done */
  722.          blind = FALSE;       /* Denote not a blind header           */
  723.       }
  724.       else if (isspace(*buf)) /* Another address?                    */
  725.          token = buf;         /* Yes --> Write it out                */
  726.       else {                  /* No --> Determine what next header is*/
  727.          blind = FALSE;       /* Assume not a blind header           */
  728.          if (equalni(&cc[offset], buf, cclen))   /* Cc: header?       */
  729.             token = strpbrk(buf," \t");
  730.          else if (equalni(&bcc[offset], buf, bcclen))  /* Bcc: header?*/
  731.          {
  732.             token = strpbrk(buf ," \t");
  733.             blind = TRUE;
  734.          } /* if */
  735.          else                 /* Unsupported header, exit loop       */
  736.             token = NULL;
  737.       } /* else */
  738.       if ( ! blind )
  739.          fputs(buf, dataout );
  740.    } while (token != NULL );
  741.  
  742. /*--------------------------------------------------------------------*/
  743. /*                   Return address list to caller                    */
  744. /*--------------------------------------------------------------------*/
  745.  
  746.    return addrlist;
  747.  
  748. } /* Parse822 */
  749.  
  750. /*--------------------------------------------------------------------*/
  751. /*    C o p y T e m p                                                 */
  752. /*                                                                    */
  753. /*    Copy the un-parsed parts of a message into the holding file     */
  754. /*--------------------------------------------------------------------*/
  755.  
  756. static boolean CopyTemp( void )
  757. {
  758.    boolean header = TRUE;
  759.    char buf[BUFSIZ];
  760.    boolean newline = TRUE;
  761.  
  762.    while (fgets(buf, BUFSIZ, datain) != NULL)
  763.    {
  764.       if (header)
  765.       {
  766.          if (*buf == '\n')
  767.             header = FALSE;
  768.          else if (equalni(received, buf, receivedlen))
  769.             hops++;
  770.       }
  771.  
  772.       newline = buf[ strlen( buf ) - 1 ] == '\n';
  773.  
  774.       if (fputs(buf, dataout) == EOF)  /* I/O error?                 */
  775.       {
  776.          printerr(tempname);
  777.          printmsg(0,"I/O error on \"%s\"", tempname);
  778.          fclose(dataout);
  779.          return FALSE;
  780.       } /* if */
  781.    } /* while */
  782.  
  783.    if (ferror(datain))        /* Clean end of file on input?         */
  784.    {
  785.       printerr(namein);
  786.       Terminate(3);
  787.    }
  788.  
  789.    if ( !newline )            /* Is the file terminated properly?    */
  790.    {
  791.       printmsg(0, "rmail: Improperly formed message, adding final newline!");
  792.       fputc( '\n', dataout );
  793.    }
  794.  
  795.    return header;
  796. }  /* CopyTemp */
  797.  
  798. /*--------------------------------------------------------------------*/
  799. /*    D a e m o n M a i l                                             */
  800. /*                                                                    */
  801. /*    Send text in a mailbag file to address(es) specified by address */
  802. /*--------------------------------------------------------------------*/
  803.  
  804. static boolean DaemonMail( const char *subject,
  805.                           char **address,
  806.                           int count )
  807. {
  808.    char buf[BUFSIZ];
  809.    char *logname;
  810.    char *token;
  811.    char *moi = NULL;
  812.    struct UserTable *userp;
  813.    char *header = "To:";
  814.    char *cc     = "Cc:";
  815.    boolean print = TRUE;
  816.  
  817. /*--------------------------------------------------------------------*/
  818. /*                         Validate the input                         */
  819. /*--------------------------------------------------------------------*/
  820.  
  821.    if ( count == 0 )
  822.    {
  823.       printmsg(0,"rmail: No addresseses to deliver to!");
  824.       return FALSE;
  825.    }
  826.  
  827. /*--------------------------------------------------------------------*/
  828. /*                       Determine our user id                        */
  829. /*--------------------------------------------------------------------*/
  830.  
  831.    logname = getenv( LOGNAME );
  832.    if ( logname == NULL )
  833.       logname = E_mailbox;
  834.  
  835. /*--------------------------------------------------------------------*/
  836. /*              Get the name of the user, or make one up              */
  837. /*--------------------------------------------------------------------*/
  838.  
  839.    userp = checkuser(logname);   /* Locate user id in host table     */
  840.  
  841.    if ( (userp != BADUSER) && (userp->realname != NULL) )
  842.       moi = userp->realname;
  843.    else if ( equali(logname, E_postmaster) || equali(logname, POSTMASTER))
  844.       moi = "Postmaster";
  845.    else if ( equali( logname, "uucp" ))
  846.       moi = "Unix to Unix Copy";
  847.    else
  848.       moi = logname;          /* Dummy to ease formatting From: line  */
  849.  
  850. /*--------------------------------------------------------------------*/
  851. /*    Add the boilerplate the front:                                  */
  852. /*                                                                    */
  853. /*       Date, From, Organization, and Reply-To                       */
  854. /*--------------------------------------------------------------------*/
  855.  
  856.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  857.               "Received:",E_domain,compilep, compilev,
  858.               " ", now );
  859.  
  860. /*--------------------------------------------------------------------*/
  861. /*                       Generate a message-id                        */
  862. /*--------------------------------------------------------------------*/
  863.  
  864.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , E_nodename, E_domain);
  865.    PutHead("Message-ID:", buf, dataout , FALSE );
  866.    PutHead(NULL, NULL, dataout , FALSE );
  867.  
  868.    PutHead("Date:", arpadate() , dataout, FALSE);
  869.  
  870.    if (bflag[F_BANG])
  871.       sprintf(buf, "(%s) %s!%s", moi, E_nodename, logname );
  872.    else {
  873.       checkname( E_nodename );  /* Force loading of the E_fdomain name */
  874.       sprintf(buf, "\"%s\" <%s@%s>", moi, logname , E_fdomain );
  875.    }
  876.  
  877.    PutHead("From:", buf, dataout, FALSE );
  878.  
  879.    if (E_organization != NULL )
  880.       PutHead("Organization:", E_organization, dataout, FALSE);
  881.  
  882. /*--------------------------------------------------------------------*/
  883. /*                      Write the address out                         */
  884. /*--------------------------------------------------------------------*/
  885.  
  886.    while( (count-- > 0) && print )
  887.    {
  888.       token = *address++;
  889.       if ( *token == '-')  /* Option flag?                        */
  890.       {
  891.          if (token[1] == 'c')
  892.          {
  893.             header = cc;
  894.             cc = "";
  895.          }
  896.          else if (token[1] == 'b')
  897.             print = FALSE;
  898.          else
  899.             printmsg(0,"rmail: Invalid flag \"%s\" ignored!", token);
  900.       } /* if ( token == '-') */
  901.       else if ( print )
  902.       {
  903.          if (strpbrk(token,"!@") == nil(char))
  904.          {
  905.             if (bflag[F_BANG])
  906.                sprintf(buf, "%s!%s", E_nodename, token );
  907.             else
  908.                sprintf(buf, "%s@%s", token , E_fdomain );
  909.             token = buf;
  910.          }
  911.  
  912.          PutHead(header , token, dataout, FALSE);
  913.          header = "";         /* Continue same field by default      */
  914.       }
  915.    } /* while( (count-- > 0) && print ) */
  916.  
  917. /*--------------------------------------------------------------------*/
  918. /*                     Handle the subject, if any                     */
  919. /*--------------------------------------------------------------------*/
  920.  
  921.    if (subject != NULL)
  922.       PutHead("Subject:", subject, dataout, FALSE);
  923.  
  924.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header line   */
  925.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header file   */
  926.  
  927. /*--------------------------------------------------------------------*/
  928. /*                          Return to caller                          */
  929. /*--------------------------------------------------------------------*/
  930.  
  931.    uuser = ruser = strncpy(fromuser, logname, sizeof fromuser);
  932.                               /* Define user for UUCP From line      */
  933.    fromuser[ sizeof fromuser - 1 ] = '\0';
  934.    rnode = bflag[F_BANG] ? E_nodename : E_fdomain;
  935.                               /* Use full domain address, if possible */
  936.  
  937.    strcpy(fromnode, E_nodename);/* Declare as local system           */
  938.    return TRUE;
  939.  
  940. } /*DaemonMail*/
  941.  
  942. /*--------------------------------------------------------------------*/
  943. /*    P u t H e a d                                                   */
  944. /*                                                                    */
  945. /*    Write one line of an RFC-822 header                             */
  946. /*--------------------------------------------------------------------*/
  947.  
  948.  static void PutHead( const char *label,
  949.                       const char *operand,
  950.                       FILE *stream,
  951.                       const boolean resent)
  952.  {
  953.    static boolean terminate = TRUE;
  954.  
  955.    if (label == NULL )        /* Terminate call?                     */
  956.    {                          /* Yes --> Reset Flag and return       */
  957.       fputc('\n', stream);    /* Terminate the current line          */
  958.       terminate = TRUE;
  959.       return;
  960.    } /* if */
  961.  
  962.    if (strlen(label))         /* First line of a header?             */
  963.    {
  964.       if (!terminate)         /* Terminate previous line?            */
  965.          fputc('\n', stream);
  966.  
  967.       if (resent)
  968.          fprintf(stream,"Resent-%s %s",label, operand);
  969.       else
  970.          fprintf(stream,"%-10s %s",label, operand);
  971.       terminate = FALSE;          /* Flag that we did not end file   */
  972.    } /* if */
  973.    else                       /* Continuing line                     */
  974.       fprintf(stream,",\n%-10s %s",label, operand);
  975.  } /* PutHead */
  976.  
  977. /*--------------------------------------------------------------------*/
  978. /*    u s a g e                                                       */
  979. /*                                                                    */
  980. /*    Report how the program works                                    */
  981. /*--------------------------------------------------------------------*/
  982.  
  983.  static void usage( void )
  984.  {
  985.  
  986.    static char syntax[] =
  987.       "Usage:\tRMAIL\t-t [-x debug] [-f | -F file]\n"
  988.       "\t\t-w [-x debug] [-f | -F file] [-s subject] addr1 [-c] addr2  [-b] addr3 ...\n"
  989.       "\t\t[-x debug] [-f | -F file] addr1 addr2 addr3 ...\n";
  990.  
  991.    puts( syntax );
  992.    exit(3);
  993.  }
  994.